package com.lmc.gobang.game;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lmc.gobang.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

//匹配器，负责玩家的匹配工作
@Slf4j
@Component
public class Matcher {
    private final Queue<User> normalQueue = new LinkedList<>();
    private final Queue<User> highlQueue = new LinkedList<>();
    private final Queue<User> veryHighQueue = new LinkedList<>();

    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private RoomManager roomManager;
    @Autowired
    private ObjectMapper objectMapper;

    public void add(User user) {
        int score = user.getScore();
        if(score<2000){
            synchronized (normalQueue) {
                normalQueue.offer(user);
                normalQueue.notify();
            }
            log.info("玩家"+user.getUsername()+"加入到了normalnormalQueue队列中");
        }else if(score>=2000 && score<3000){
            synchronized (highlQueue) {
                highlQueue.offer(user);
                highlQueue.notify();
            }
            log.info("玩家"+user.getUsername()+"加入到了highlQueue队列中");
        }else{
            synchronized (veryHighQueue) {
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }
            log.info("玩家"+user.getUsername()+"加入到了veryHighQueue队列中");
        }
    }

    public void remore(User user) {
        int score = user.getScore();
        if(score<2000){
            synchronized (normalQueue) {
                normalQueue.remove(user);
                log.info("玩家"+user.getUsername()+"离开了normalQueue队列中");
            }
        }else if(score>=2000 && score<3000){
            synchronized (highlQueue) {
                highlQueue.remove(user);
                log.info("玩家"+user.getUsername()+"离开了highlQueue队列中");
            }
        }else{
            synchronized (veryHighQueue) {
                veryHighQueue.remove(user);
                log.info("玩家"+user.getUsername()+"离开了veryHighQueue队列中");
            }
        }
    }

    public Matcher(){
        //创建三个线程，分别管理三个匹配队列
        Thread t1 = new Thread(){
            @Override
            public void run() {
                //扫描normalQueue
                while(true){
                    handlerMatch(normalQueue);
                }
            }


        };
        t1.start();
        Thread t2 = new Thread(){
            @Override
            public void run() {
                //扫描highlQueue
                while(true){
                    handlerMatch(highlQueue);
                }
            }
        };
        t2.start();
        Thread t3 = new Thread(){
            @Override
            public void run() {
                //扫描veryHighQueue
                while(true){
                    handlerMatch(veryHighQueue);
                }
            }
        };
        t3.start();
    }

    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue) {
            try {
                //1.判断队列中是否有足够的玩家
                //  因为可能是0个玩家
                //  如果加入一个玩家后，仍然不能进行后续匹配操作
                //  所以不能是if而应是while
                while (matchQueue.size()<2){
                    matchQueue.wait();
                }
                //2.尝试从队列中取出两个玩家
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                log.info("匹配到了两个玩家:玩家一："+player1.getUsername()+"  玩家二"+player2.getUsername());
                //3.获取玩家的websockersession对话，为了后面给玩家发送匹配成功的消息
                WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());
                log.info("已获取两个玩家的session信息");
                //再次判断玩家是否为空(虽然前面已经判断过了)
                if(session1==null){
                    //如果玩家中途离开，把另外一个玩家放回队列中
                    matchQueue.offer(player2);
                    return;
                }
                if(session2==null){
                    //如果玩家中途离开，把另外一个玩家放回队列中
                    matchQueue.offer(player1);
                    return;
                }
                //判断两个用户是否相同（理论上不会存在，因为前面已经设置了禁止多开）
                if(session1==session2){
                    //只需把其中一个放回到队列中
                    matchQueue.offer(player1);
                    return;
                }

                //4.把两个玩家放到同一个游戏房间内
                Room room = new Room();
                roomManager.add(room, player1.getUserId(), player2.getUserId());
                log.info("已将两个玩家放入同一个游戏房间");

                //5.告诉玩家已经匹配到了
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                String json1 = objectMapper.writeValueAsString(response1);
                synchronized (session1) {
                    session1.sendMessage(new TextMessage(json1));

                    log.info("已发送匹配成功的消息给玩家一："+player1.getUsername());
                }

                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                String json2 = objectMapper.writeValueAsString(response2);
                synchronized (session2) {
                    session2.sendMessage(new TextMessage(json2));
                    log.info("已发送匹配成功的消息给玩家二："+player2.getUsername());
                }
                // 匹配完成后应确保用户不再留在队列中
                matchQueue.poll(); // 已经取出 player1
                matchQueue.poll(); // 已经取出 player2
            } catch (IOException | InterruptedException e) {
                log.error(e.getMessage());
                e.printStackTrace();
            }
        }
    }

}
